/*******************************************************************************
 * Copyright (c) 2012, 2013 XML-Print Project.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     XML-Print Project - initial API and implementation
 ******************************************************************************/
package info.xmlprint.ui.widgets;

import info.xmlprint.core.format.Format;
import info.xmlprint.core.format.FormatGroup;
import info.xmlprint.core.mapping.Mapping;
import info.xmlprint.core.mapping.MappingGroup;
import info.xmlprint.core.project.PrintProject;
import info.xmlprint.ui.message.GuiMessages;
import info.xmlprint.util.FileUtil;
import info.xmlprint.util.ResizeColumns;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

public class ImportSetupViewer implements ISubjectControl {

	// 3 Columen Fuer Tabelle und Title
	private final int COL_CURRENT = 0;

	private final int COL_IMPORT = 1;

	private final int COL_NEW = 2;

	private final Color COLOR_DISABLED = Display.getDefault().getSystemColor(
			SWT.COLOR_GRAY);

	// Color
	private final Color COLOR_IGNORE = Display.getDefault().getSystemColor(
			SWT.COLOR_BLACK);

	private final Color COLOR_NEW = Display.getDefault().getSystemColor(
			SWT.COLOR_BLUE);

	private final Color COLOR_NORMAL = Display.getDefault().getSystemColor(
			SWT.COLOR_BLACK);

	private final Color COLOR_REPLACE = Display.getDefault().getSystemColor(
			SWT.COLOR_RED);
	private final String[] columsNamesForFormat = new String[] {
			GuiMessages.Stileditor_Gui_Import_colsNew + " "
					+ GuiMessages.Stileditor_Gui_Formats,
			GuiMessages.Stileditor_Gui_Import_colsAction,
			GuiMessages.Stileditor_Gui_Import_colsImportName };
	private final String[] columsNamesForMapping = new String[] {
			GuiMessages.Stileditor_Gui_Import_colsNew + " "
					+ GuiMessages.General_Gui_Mappings,
			GuiMessages.Stileditor_Gui_Import_colsAction,
			GuiMessages.Stileditor_Gui_Import_colsImportName };

	private FormatGroup currentFormatGroup, inputFormagGroup;
	private MappingGroup currentMappingGroup, inputMappingGroup;
	private ArrayList<ImportItem> formatImportList;
	private final int IMPORT_TYPE_IGNORE = 0;

	private final int IMPORT_TYPE_NEW = 1;
	private final int IMPORT_TYPE_REPLACE = 2;
	// ComboListe Title
	private String[] importType = new String[] {
			GuiMessages.Stileditor_Gui_Import_ignore,
			GuiMessages.Stileditor_Gui_Import_new,
			GuiMessages.Stileditor_Gui_Import_replace };
	private ArrayList<ImportItem> mappingImportList;
	private List<IObserverControl> observerList = new ArrayList<IObserverControl>();

	// Wizard page
	private final int WIZARD_TYPE_FORMAT = 1;
	private final int WIZARD_TYPE_MAPPING = 2;

	private class FormatPage extends WizardPage {
		protected FormatPage(String pageName) {
			super(pageName);
		}

		// TODO: Strings externalisieren
		@Override
		public void createControl(Composite parent) {
			Composite topComp = new Composite(parent, SWT.NULL);
			setTitle("Import der Formate");
			setMessage("Wie soll mit existierenden Formaten umgegangen werden?");
			addTableViewer(topComp, WIZARD_TYPE_FORMAT);
			setControl(topComp);
		}

	}

	private class ImportItem {
		// 0=ignore, 1=als neue, 2=ueberschreiben
		private int importType = IMPORT_TYPE_NEW;

		private String newName;

		private Object obj;

		private String oldName;

		public int getImportType() {
			return importType;
		}

		public String getNewName() {
			return newName;
		}

		public Object getObj() {
			return obj;
		}

		public String getOldName() {
			return oldName;
		}

		public void setImportType(int importType) {
			this.importType = importType;
		}

		public void setNewName(String newName) {
			this.newName = newName;
		}

		public void setObj(Object obj) {
			this.obj = obj;
		}

		public void setOldName(String oldName) {
			this.oldName = oldName;
		}
	}

	private class ImportWizard extends Wizard {
		private FormatPage formatPage;
		private MappingPage mappingPage;

		public void addPages() {
			formatPage = new FormatPage("FormatImportWizard");

			addPage(formatPage);

			if (inputMappingGroup != null) {
				mappingPage = new MappingPage("MappingImportWizard");
				addPage(mappingPage);
			}
		}

		public boolean canFinish() {
			if (currentMappingGroup != null && inputMappingGroup != null
					&& this.getContainer().getCurrentPage() != mappingPage) {
				return false;
			}

			return super.canFinish();
		}

		@Override
		public boolean performFinish() {

			if (formatImportList != null)
				for (ImportItem elem : formatImportList) {
					switch (elem.getImportType()) {

					// ignore
					case IMPORT_TYPE_IGNORE:
						break;

					// als neue
					case IMPORT_TYPE_NEW: {
						Format newFormat = (Format) elem.getObj();
						newFormat.setName(elem.getNewName());
						if (newFormat.getType().equalsIgnoreCase("standard")) {
							newFormat.setType("");
						}
						currentFormatGroup.addFormat(newFormat);
					}
						break;

					// ueberschreiben
					case IMPORT_TYPE_REPLACE: {
						Format newFormat = (Format) elem.getObj();
						newFormat.setName(elem.getNewName());
						Format oldFormat = currentFormatGroup
								.getFormatByName(elem.getOldName());

						if (currentFormatGroup.getStandardFormat().equals(
								oldFormat)) {
							newFormat.setType("standard");
							newFormat.setName(elem.getOldName());
							currentFormatGroup.addFormat(newFormat);
						} else
							currentFormatGroup.addFormat(newFormat);

						// mapping aktualisieren
						if (currentMappingGroup != null)
							for (Mapping m : currentMappingGroup.getList()) {
								if (oldFormat.equals(m.getFormat())) {
									m.setFormat(newFormat);
								}
							}

						currentFormatGroup.removeFormat(oldFormat);
					}
						break;
					}
				}

			if (mappingImportList != null)
				for (ImportItem elem : mappingImportList) {
					Mapping newMapping = (Mapping) elem.getObj();
					newMapping.setName(elem.getNewName());
					switch (elem.getImportType()) {
					// ignore
					case IMPORT_TYPE_IGNORE:
						break;

					// als neue
					case IMPORT_TYPE_NEW: {
						if (newMapping.getFormat() != null) {

							if (newMapping.getFormat().getType()
									.equalsIgnoreCase("standard")) {
								newMapping.setFormat(currentFormatGroup
										.getStandardFormat());
							} else if (newMapping.getFormat().getType()
									.equalsIgnoreCase("ignore"))
								newMapping.setFormat(currentFormatGroup
										.getIgnoreFormat());
						}

						if (!currentMappingGroup.getFormatGroup().hasFormat(
								newMapping.getFormat())) {
							// wenn Format nicht exitiert
							newMapping.setFormat(null);
						}
						currentMappingGroup.add(newMapping);
					}
						break;

					// ueberschreiben
					case IMPORT_TYPE_REPLACE: {
						if (newMapping.getFormat() != null
								&& newMapping.getFormat().getType()
										.equalsIgnoreCase("standard")) {
							newMapping.setFormat(currentFormatGroup
									.getStandardFormat());
						}

						for (Mapping oldMapping : currentMappingGroup
								.getMappingsByName(elem.getOldName())) {
							currentMappingGroup.remove(oldMapping);
						}

						currentMappingGroup.add(newMapping);
					}
						break;
					}
				}
			notifyObservers();
			return true;
		}

	}

	private class MappingPage extends WizardPage {
		protected MappingPage(String pageName) {
			super(pageName);
		}

		@Override
		public void createControl(Composite parent) {
			Composite topComp = new Composite(parent, SWT.NULL);
			setTitle("Import der Zuweisungen");
			setMessage("Wie soll mit existierenden Zuweisungen umgegangen werden?");
			addTableViewer(topComp, WIZARD_TYPE_MAPPING);
			setControl(topComp);
		}

	}

	private class setTableVeiwerContentProvider implements
			IStructuredContentProvider {

		@Override
		public void dispose() {
		}

		@SuppressWarnings("unchecked")
		@Override
		public Object[] getElements(Object arg0) {
			if (arg0 instanceof List) {
				return ((List<ImportItem>) arg0).toArray();
			}
			return null;
		}

		@Override
		public void inputChanged(Viewer arg0, Object arg1, Object arg2) {
		}

	}

	private class setTableViewerLabelProvider implements ITableLabelProvider {

		@Override
		public void addListener(ILabelProviderListener arg0) {
		}

		@Override
		public void dispose() {

		}

		@Override
		public Image getColumnImage(Object arg0, int index) {
			return null;
		}

		@Override
		public String getColumnText(Object arg0, int index) {
			if (arg0 instanceof ImportItem) {
				ImportItem elem = (ImportItem) arg0;
				switch (index) {
				case COL_CURRENT:
					return elem.getOldName();
				case COL_IMPORT:
					return importType[elem.getImportType()];
				case COL_NEW:
					return elem.getNewName();
				}
			}

			return null;
		}

		@Override
		public boolean isLabelProperty(Object arg0, String arg1) {
			return false;
		}

		@Override
		public void removeListener(ILabelProviderListener arg0) {
		}
	}

	public ImportSetupViewer(FormatGroup oldFg, FormatGroup newFg, PrintProject pProject) {
		this.currentFormatGroup = oldFg;
		this.inputFormagGroup = newFg;
		this.currentMappingGroup = pProject.getMappingGroup();
		
	} 
	
	public ImportSetupViewer(MappingGroup oldMg, MappingGroup newMg) {
		this.currentMappingGroup = oldMg;
		this.inputMappingGroup = newMg; 
		if (oldMg != null) {
			currentFormatGroup = oldMg.getFormatGroup();
		}

		if (newMg != null) {
			inputFormagGroup = newMg.getFormatGroup();
		}
 
	}

	private void addTableViewer(Composite parent, final int wizardPageType) {
		final TableViewer tableViewer = new TableViewer(parent,
				SWT.FULL_SELECTION);

		final Table table = tableViewer.getTable();
		table.setHeaderVisible(true);
		table.setLinesVisible(true);

		// Columen Title definieren
		String colsNames[];
		if (wizardPageType == WIZARD_TYPE_FORMAT) {
			colsNames = columsNamesForFormat;
		} else {
			colsNames = columsNamesForMapping;
		}

		for (String s : colsNames) {
			new TableColumn(table, SWT.LEFT).setText(s);
		}

		tableViewer.setContentProvider(new setTableVeiwerContentProvider());
		tableViewer.setLabelProvider(new setTableViewerLabelProvider());

		ArrayList<ImportItem> itemList = new ArrayList<ImportItem>();
		ArrayList<ImportItem> sameList = new ArrayList<ImportItem>();
		ArrayList<ImportItem> newList = new ArrayList<ImportItem>();

		String newName;
		ArrayList<String> newNamesList = new ArrayList<String>();
		if (wizardPageType == WIZARD_TYPE_FORMAT) {
			for (Format f : inputFormagGroup.getFormats()) {
				if (f.getType().equalsIgnoreCase("ignore"))
					continue;

				ImportItem item = new ImportItem();
				item.setObj(f);
				newName = f.getName();

				// wenn keinen selben Name vorhanden ist
				// generiert einen neuen Name
				if (!currentFormatGroup.hasElement(newName)
						&& (newName = createNewName(newName,
								currentFormatGroup, newNamesList)) != null) {
					item.setNewName(newName);
					newList.add(item);

				} else {
					item.setOldName(f.getName());
					sameList.add(item);
					if ((newName = createNewName(newName, currentFormatGroup,
							newNamesList)) != null)
						item.setNewName(newName);
				}
			}

		} else if (wizardPageType == WIZARD_TYPE_MAPPING) {
			for (Mapping m : inputMappingGroup.getList()) {
				newName = m.getName();
				ImportItem item = new ImportItem();

				item.setObj(m);

				if (!currentMappingGroup.hasElement(newName)
						&& (newName = createNewName(newName,
								currentMappingGroup, newNamesList)) != null) {
					newList.add(item);
					item.setNewName(newName);

				} else {
					sameList.add(item);
					item.setOldName(newName);

					if ((newName = createNewName(newName, currentMappingGroup,
							newNamesList)) != null)
						item.setNewName(newName);
				}
			}
		}

		itemList.addAll(sameList);
		itemList.addAll(newList);

		if (wizardPageType == WIZARD_TYPE_FORMAT) {
			formatImportList = itemList;
		} else if (wizardPageType == WIZARD_TYPE_MAPPING) {
			mappingImportList = itemList;
		}

		tableViewer.setInput(itemList);

		setTableColor(tableViewer, null);

		final TableEditor editor = new TableEditor(table);

		// alle
		table.addListener(SWT.MenuDetect, new Listener() {
			public void handleEvent(Event event) {
				Menu menu = new Menu(table.getShell(), SWT.POP_UP);

				for (final int i : new Integer[] { IMPORT_TYPE_IGNORE,
						IMPORT_TYPE_NEW, IMPORT_TYPE_REPLACE }) {
					{
						MenuItem mi = new MenuItem(menu, SWT.PUSH);
						mi.setText("Alle \"" + importType[i] + "\"");
						mi.addSelectionListener(new SelectionAdapter() {
							@Override
							public void widgetSelected(SelectionEvent e) {
								@SuppressWarnings("unchecked")
								ArrayList<ImportItem> list = (ArrayList<ImportItem>) tableViewer
										.getInput();
								if (list != null) {
									for (ImportItem item : list) {
										if (item.getOldName() == null
												&& i == IMPORT_TYPE_REPLACE)
											continue;

										item.setImportType(i);
									}
									setTableColor(tableViewer, null);
								}
							}
						});
					}
				}
				menu.setVisible(true);
			}
		});

		table.addListener(SWT.MouseDown, new Listener() {
			public void handleEvent(Event e) {
				Point pt = new Point(e.x, e.y);
				final TableItem tableItem = table.getItem(pt);

				if (editor.getEditor() != null) {
					editor.getEditor().dispose();
				}

				if (tableItem == null)
					return;

				for (int i = 0; i < table.getColumnCount(); i++) {
					Rectangle rect = tableItem.getBounds(i);
					if (rect.contains(pt)) {
						// combo
						final ImportItem elem = (ImportItem) tableItem
								.getData();

						if (i == COL_IMPORT) {
							final Combo combo = new Combo(table, SWT.NONE);
							combo.add(importType[0]);
							combo.add(importType[1]);
							if (elem.getOldName() != null
									&& elem.getOldName().length() > 0) {
								combo.add(importType[2]);
							}

							combo.select(elem.getImportType());
							combo.addListener(SWT.Selection, new Listener() {
								public void handleEvent(Event arg0) {
									elem.setImportType(combo
											.getSelectionIndex());
									setTableColor(tableViewer, tableItem);
									if (elem.getImportType() == IMPORT_TYPE_IGNORE
											|| (elem.getImportType() == IMPORT_TYPE_REPLACE && elem
													.getOldName().equals(
															"Standard"))) {
										tableItem.setForeground(COL_NEW,
												COLOR_DISABLED);
									} else {
										tableItem.setForeground(COL_NEW,
												COLOR_NORMAL);
									}
								}

							});

							combo.pack();
							editor.minimumWidth = combo.getSize().x;
							editor.horizontalAlignment = SWT.LEFT;
							editor.setEditor(combo, tableItem, COL_IMPORT);

						} else if (i == COL_NEW) {
							// wenn Schrift in Grau, dann nicht editierbar
							if (tableItem != null
									&& tableItem.getForeground(i).equals(
											COLOR_DISABLED)) {
								return;
							}

							final Text text = new Text(table, SWT.BORDER);
							text.setText(elem.getNewName());
							text.pack();
							editor.horizontalAlignment = SWT.LEFT;
							editor.minimumWidth = table.getColumn(COL_NEW)
									.getWidth() - 10;
							editor.setEditor(text, tableItem, COL_NEW);

							text.addListener(SWT.FocusOut, new Listener() {
								@Override
								public void handleEvent(Event arg0) {
									String newStr = text.getText();
									boolean hasName = false;

									// testen, ob name vorhanden ist;
									if (wizardPageType == WIZARD_TYPE_FORMAT) {
										if (elem.getImportType() == IMPORT_TYPE_NEW
												&& currentFormatGroup != null
												&& currentFormatGroup
														.hasElement(newStr)) {
											hasName = true;
										}
									}

									for (TableItem ti : table.getItems()) {
										if (ti.equals(tableItem))
											continue;
										if (ti.getText(COL_NEW).equals(newStr)) {
											hasName = true;
										}
									}

									if (hasName) {
										MessageDialog
												.openError(
														null,
														null,
														GuiMessages.Stileditor_Error_FormatExists);
										return;
									}

									elem.setNewName(text.getText());

									setTableColor(tableViewer, null);
								}
							});

						}
					}
				}
			}
		});

		parent.addControlListener(new ResizeColumns(parent, table));

	}

	private String createNewName(String name, IGroup igroup,
			ArrayList<String> nameList) {
		int i = 0;
		String newName = name;
		;
		while (true) {
			if (!nameList.contains(newName) && !igroup.hasElement(newName)) {
				nameList.add(newName);
				return newName;
			}
			i++;
			newName = name + "_" + i;
		}
	}

	private void initGui() {
		Display display = Display.getDefault();
		Shell shell = new Shell(display, SWT.APPLICATION_MODAL | SWT.MAX
				| SWT.MIN | SWT.RESIZE);

		int maxW = shell.getMonitor().getClientArea().width - 100;
		int maxH = shell.getMonitor().getClientArea().height - 100;
		maxW = maxW > 800 ? 800 : maxW;
		maxH = maxH > 500 ? 500 : maxH;
		shell.setSize(maxW, maxH);
		shell.layout();
		FileUtil.shellSetCenter(shell);

		WizardDialog dialog = new WizardDialog(shell, new ImportWizard());
		dialog.setPageSize(shell.getSize());
		dialog.open();

		shell.dispose();

	}

	@Override
	public void notifyObservers() {
		for (IObserverControl o : observerList) {
			o.updateControl();
		}
	}

	//
	// @Override
	// public void notifyChanged() {
	// if (parentContainer != null && parentContainer instanceof ISetupViewer)
	// ((ISetupViewer) parentContainer).updateViewer();
	//
	// }

	public void Open() {
		initGui();
	}

	@Override
	public void registerObserver(IObserverControl observer) {
		observerList.add(observer);
	}

	@Override
	public void removeObserver(IObserverControl observer) {
		observerList.remove(observer);
	}

	private void setTableColor(TableViewer tv, TableItem tableItem) {
		if (tableItem != null) {
			setTableItemForeground(tableItem);
			tv.refresh(tableItem.getData());
			return;
		}

		for (TableItem ti : tv.getTable().getItems()) {
			setTableItemForeground(ti);
		}
		tv.refresh();
	}

	private void setTableItemForeground(TableItem tableItem) {
		ImportItem elem = (ImportItem) tableItem.getData();

		switch (elem.getImportType()) {
		case IMPORT_TYPE_IGNORE:
			tableItem.setForeground(COL_IMPORT, COLOR_IGNORE);
			break;

		case IMPORT_TYPE_NEW:
			tableItem.setForeground(COL_IMPORT, COLOR_NEW);
			break;
		case IMPORT_TYPE_REPLACE:
			tableItem.setForeground(COL_IMPORT, COLOR_REPLACE);
			break;
		}

	}

}
